package com.apetrenko.avaya.callstore.client;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTMLTable;
import com.google.gwt.user.client.ui.Hyperlink;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;

public class BaseTable extends FlexTable implements IUpdatableTable {

	private class BaseTableListener implements ClickHandler {

		@Override
		public void onClick(ClickEvent aEvent) {
			Cell vCell = BaseTable.this.getCellForEvent(aEvent);
			if ((vCell.getRowIndex() - FIRST_DATA_ROW) >= 0) {
				setSelection(vCell.getRowIndex() - FIRST_DATA_ROW);
			}
			return;
		}

	}

	private class RefreshListener implements ClickHandler {

		@Override
		public void onClick(ClickEvent aEvent) {
			if (!iUpdating) {
				update();
			}
		}
	}

	private static final String ST_ODDROW = "apetrenko-BaseTable-OddRow";
	private static final String ST_EVENROW = "apetrenko-BaseTable-EvenRow";
	private static final String ST_SELROW = "apetrenko-BaseTable-SelectedRow";

	private static final String ST_TABLE = "apetrenko-BaseTable";
	private static final String ST_TBLCONTROL = "apetrenko-BaseTable-Control";
	private static final String ST_TBLREFRESH = "apetrenko-BaseTable-Control-Refresh";
	private static final String ST_TBLHEADER = "apetrenko-BaseTable-Header";

	private static final String ST_COLHEADER = "apetrenko-BaseTable-ColumnHeader";
	private static final String ST_COLHEADERTEXT = "apetrenko-BaseTable-ColumnHeaderText";

	private static final int FIRST_DATA_ROW = 2;
	private static final int FIRST_COLUMN = 0;
	private static final int HEADER_ROW = 1;
	private static final int CONTROL_ROW = 0;
	private static final int DEFAULT_TABLE_CELL_SPACING = 0;

	private boolean iUpdating;
	private ContentProvider iContentProvider;
	private LabelProvider iLabelProvider;
	private int iSelectedRowIndex = -1;
	private int iRowCount;
	private Object[] iItems;
	private Hyperlink iRefreshLink;

	public BaseTable() {
		insertRow(CONTROL_ROW);
		getRowFormatter().addStyleName(CONTROL_ROW, ST_TBLCONTROL);
		iRefreshLink = new Hyperlink("Обновить", "");
		iRefreshLink.addClickHandler(new RefreshListener());
		setWidget(0, 0, iRefreshLink);
		iRefreshLink.addStyleName(ST_TBLREFRESH);
		insertRow(HEADER_ROW);
		getRowFormatter().addStyleName(HEADER_ROW, ST_TBLHEADER);
		setCellSpacing(DEFAULT_TABLE_CELL_SPACING);
		addStyleName(ST_TABLE);
		this.addClickHandler(new BaseTableListener());
	}

	public void setSelection(int aIndex) {
		iSelectedRowIndex = aIndex;
		updateStyles();
	}

	public void update() {
		startUpdating();
		iContentProvider.requestUpdate();		
	}

	private void startUpdating() {
		iUpdating = true;
		iRefreshLink.setText("Получение данных...");
	}

	public void doUpdate(Object[] aItems) {
		iItems = aItems;
		updateData();
		updateStyles();
		finishUpdating(true);
	}

	private void finishUpdating(boolean aSuccess) {
		if (aSuccess) {
			iRefreshLink.setText("Обновить");
		} else {
			iRefreshLink.setText("Ошибка при обновлении!");
		}
		iSelectedRowIndex = -1;
		iUpdating = false;
	}

	private void updateData() {
		clearData();
		for (int i = 0; i < iItems.length; ++i) {
			addRow(iItems[i]);
		}
	}

	private void clearData() {
		iSelectedRowIndex = -1;
		int vCount = getRowCount();
		vCount = vCount - FIRST_DATA_ROW;

		for (int i = FIRST_DATA_ROW; i < vCount; i++) {
			removeRow(FIRST_DATA_ROW);
		}
		iRowCount = 0;
	}

	public void addColumn(Object columnHeading) {
		Widget widget = createCellWidget(columnHeading);
		int columnIndex = getColumnCount();

		widget.setWidth("100%");
		widget.addStyleName(ST_COLHEADERTEXT);

		setWidget(HEADER_ROW, columnIndex, widget);

		getCellFormatter().addStyleName(HEADER_ROW, columnIndex, ST_COLHEADER);
		FlexCellFormatter cf = (FlexCellFormatter) getCellFormatter();
		cf.setColSpan(CONTROL_ROW, FIRST_COLUMN, getColumnCount());
	}

	public int getColumnCount() {
		return getCellCount(HEADER_ROW);
	}

	private void addRow(Object aRowObject) {
		for (int vCell = FIRST_COLUMN; vCell < getColumnCount(); vCell++) {
			addCell(iRowCount, vCell, aRowObject);
		}
		iRowCount++;
	}

	private void addCell(int aRow, int aColumn, Object aValue) {
		Widget vWidget = iLabelProvider.getCellWidget(aRow, aColumn, aValue);
		String vStyle = iLabelProvider.getCellStyle(aRow, aColumn, aValue);
		setWidget(aRow + FIRST_DATA_ROW, aColumn, vWidget);
		getCellFormatter().addStyleName(aRow + FIRST_DATA_ROW, aColumn, "apetrenko-BaseTable-Cell");
		getCellFormatter().addStyleName(aRow + FIRST_DATA_ROW, aColumn, vStyle);
		
	}

	private void updateStyles() {
		HTMLTable.RowFormatter rf = getRowFormatter();

		for (int row = FIRST_DATA_ROW; row < getRowCount(); ++row) {
			if ((row % 2) != 0) {
				// Remove the even row style, just in case this used
				// to be an even row
				rf.removeStyleName(row, ST_SELROW);
				rf.removeStyleName(row, ST_EVENROW);
				rf.addStyleName(row, ST_ODDROW);
			} else {
				// Remove the odd row style, just in case this used
				// to be an odd row
				rf.removeStyleName(row, ST_SELROW);
				rf.removeStyleName(row, ST_ODDROW);
				rf.addStyleName(row, ST_EVENROW);
			}
		}
		if (iSelectedRowIndex >= 0) {
			rf.removeStyleName(iSelectedRowIndex + FIRST_DATA_ROW, ST_ODDROW);
			rf.removeStyleName(iSelectedRowIndex + FIRST_DATA_ROW, ST_EVENROW);
			rf.addStyleName(iSelectedRowIndex + FIRST_DATA_ROW, ST_SELROW);
		}
	}

	public void setContentProvider(ContentProvider aContentProvider) {
		iContentProvider = aContentProvider;
		iContentProvider.setTarget(this);
	}

	public void setLabelProvider(LabelProvider aLabelProvider) {
		iLabelProvider = aLabelProvider;
	}

	protected Widget createCellWidget(Object aCellObject) {
		Widget widget = null;

		if (aCellObject instanceof Widget)
			widget = (Widget) aCellObject;
		else
			widget = new Label(aCellObject.toString());
		return widget;
	}

	public void updateFail(Throwable aCaught) {
		finishUpdating(false);

	}

	public int getDataRowIndex(int aRow) {
		return aRow >= FIRST_DATA_ROW ? (aRow - FIRST_DATA_ROW) : -1;
	}

	public Object getItem(int aIndex) {
		if ((aIndex >= 0) && (aIndex < iItems.length)) {
			return iItems[aIndex];
		} else {
			return null;
		}
	}

}